import requests
import json
import asyncio
import time
from typing import Dict, List, Any, Optional
from concurrent.futures import ThreadPoolExecutor
import logging

class theaterSaveService:
    def __init__(self, base_url: str = "http://192.168.1.4/api/v1"):
        self.base_url = base_url
        self.save_endpoint = f"{base_url}/theater/create"
        self.timeout = 60  # 增加超时时间
        self.max_retries = 3

        # 配置日志
        logging.basicConfig(level=logging.INFO)
        self.logger = logging.getLogger(__name__)

    def prepare_form_data(self, theater_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        将复杂的剧场数据转换为FormData格式 - 数组格式版本
        """
        try:
            # 基本信息
            theater_info = theater_data.get('theater_info', {})
    
            form_data = {
                # 剧场基本信息
                'title': theater_info.get('title', ''),
                'description': theater_info.get('description', ''),
                'era': theater_info.get('era', ''),
                'location': theater_info.get('location', ''),
                'author': theater_info.get('author', 'AI智能生成器'),
                'plot_summary': theater_info.get('plotSummary', ''),
    
                # 元数据
                'task_id': theater_data.get('task_id', ''),
                'generation_source': 'python_ai_generator',
                'created_at': theater_info.get('createdAt', ''),
    
                # 统计信息
                'nodes_count': str(len(theater_data.get('script_nodes', []))),
                'characters_count': str(len(theater_data.get('characters', []))),
                'skills_count': str(len(theater_data.get('available_skills', []))),
            }
    
            # 处理数组字段 - Laravel期望的格式
            # Features数组
            features = theater_info.get('features', [])
            for i, feature in enumerate(features):
                form_data[f'features[{i}]'] = str(feature)
    
            # Script nodes数组
            script_nodes = theater_data.get('script_nodes', [])
            for i, node in enumerate(script_nodes):
                form_data[f'script_nodes[{i}][id]'] = node.get('id', '')
                form_data[f'script_nodes[{i}][title]'] = node.get('title', '')
                form_data[f'script_nodes[{i}][content]'] = node.get('content', '')
                form_data[f'script_nodes[{i}][level]'] = str(node.get('level', 0))
                
                # 🔧 修复：将characterSettings转换为数组格式
                character_settings = node.get('characterSettings', {})
                
                # 如果characterSettings为空，至少创建一个空数组
                if not character_settings:
                    form_data[f'script_nodes[{i}][characterSettings][0]'] = ''
                else:
                    # 将每个character的设置转换为数组格式
                    char_index = 0
                    for char_id, char_setting in character_settings.items():
                        # 将每个character的设置作为数组的一个元素
                        setting_data = {
                            'character_id': char_id,
                            'behaviors': char_setting.get('behaviors', []),
                            'conditions': char_setting.get('conditions', []),
                            'branches': char_setting.get('branches', [])
                        }
                        
                        # 将整个设置对象作为JSON字符串存储在数组中
                        form_data[f'script_nodes[{i}][characterSettings][{char_index}]'] = json.dumps(
                            setting_data, ensure_ascii=False
                        )
                        char_index += 1
    
            # Characters数组
            characters = theater_data.get('characters', [])
            for i, char in enumerate(characters):
                form_data[f'characters[{i}][id]'] = char.get('id', '')
                form_data[f'characters[{i}][name]'] = char.get('name', '')
                form_data[f'characters[{i}][description]'] = char.get('description', '')
                form_data[f'characters[{i}][avatar]'] = char.get('avatar', '')
                
                # selectedSkills数组
                selected_skills = char.get('selectedSkills', [])
                for j, skill in enumerate(selected_skills):
                    form_data[f'characters[{i}][selectedSkills][{j}]'] = str(skill)
    
            # Available skills数组
            available_skills = theater_data.get('available_skills', [])
            for i, skill in enumerate(available_skills):
                form_data[f'available_skills[{i}]'] = str(skill)
    
            # 计算数据大小
            total_size = sum(len(str(v)) for v in form_data.values())
            self.logger.info(f"📦 FormData prepared: {form_data.get('title', 'Unknown')} - {form_data.get('nodes_count', 0)} nodes - {total_size/1024:.1f}KB")
            
            # 调试：打印characterSettings相关的FormData
            self.logger.debug("📋 CharacterSettings FormData preview:")
            for key in sorted(form_data.keys()):
                if 'characterSettings' in key:
                    value = str(form_data[key])[:100] + "..." if len(str(form_data[key])) > 100 else str(form_data[key])
                    self.logger.debug(f"   {key}: {value}")
            
            return form_data
    
        except Exception as e:
            self.logger.error(f"❌ FormData preparation failed: {e}")
            raise Exception(f"数据格式转换失败: {e}")
    
    async def save_theater_data_async(self, theater_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """
        异步保存剧场数据到Laravel接口
        """
        loop = asyncio.get_event_loop()

        def sync_save():
            return self.save_theater_data_sync(theater_data)

        with ThreadPoolExecutor() as executor:
            return await loop.run_in_executor(executor, sync_save)

    def save_theater_data_sync(self, theater_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """
        同步保存剧场数据到Laravel接口
        """
        start_time = time.time()
        
        for attempt in range(self.max_retries):
            try:
                self.logger.info(f"🚀 开始保存剧场数据 (尝试 {attempt + 1}/{self.max_retries})")

                # 准备FormData
                form_data = self.prepare_form_data(theater_data)
                prep_time = time.time()
                self.logger.info(f"📦 数据准备耗时: {prep_time - start_time:.2f}秒")
                
                # 发送请求
                request_start = time.time()
                response = requests.post(
                    self.save_endpoint,
                    data=form_data,  # 使用data参数发送FormData
                    timeout=self.timeout,
                    headers={
                        'Accept': 'application/json',
                        'User-Agent': 'Python-Theater-Generator/1.0',
                        'Connection': 'close'
                    }
                )
                
                request_time = time.time()
                self.logger.info(f"📡 请求耗时: {request_time - request_start:.2f}秒")
                self.logger.info(f"📡 Laravel响应状态: {response.status_code}")

                if response.status_code == 200 or response.status_code == 201:
                    try:
                        result = response.json()
                        self.logger.info(f"✅ 剧场数据保存成功: {form_data.get('title', 'Unknown')}")

                        if result.get('success'):
                            return {
                                'success': True,
                                'laravel_response': result,
                                'theater_id': result.get('data', {}).get('id'),
                                'title': form_data.get('title'),
                                'attempt': attempt + 1,
                                'total_time': request_time - start_time
                            }
                        else:
                            self.logger.warning(f"⚠️ Laravel返回失败状态: {result.get('message', 'Unknown error')}")
                            if attempt == self.max_retries - 1:
                                return {
                                    'success': False,
                                    'error': result.get('message', 'Laravel返回失败状态'),
                                    'laravel_response': result
                                }
                    except json.JSONDecodeError:
                        self.logger.error(f"❌ 无法解析响应JSON: {response.text[:500]}")
                        return {
                            'success': False,
                            'error': '服务器响应格式错误',
                            'response_text': response.text[:500]
                        }

                elif response.status_code == 422:
                    # 验证错误，不重试
                    try:
                        error_data = response.json()
                        self.logger.error(f"❌ 数据验证失败: {error_data}")
                        return {
                            'success': False,
                            'error': '数据验证失败',
                            'validation_errors': error_data.get('errors', {}),
                            'laravel_response': error_data
                        }
                    except json.JSONDecodeError:
                        return {
                            'success': False,
                            'error': '数据验证失败，无法解析错误详情',
                            'response_text': response.text[:500]
                        }

                else:
                    self.logger.warning(f"⚠️ HTTP错误 {response.status_code}: {response.text[:200]}")
                    if attempt == self.max_retries - 1:
                        return {
                            'success': False,
                            'error': f'HTTP {response.status_code}: {response.text[:200]}',
                            'status_code': response.status_code
                        }

                # 重试前等待
                if attempt < self.max_retries - 1:
                    wait_time = (attempt + 1) * 2  # 递增等待时间
                    self.logger.info(f"⏳ 等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)

            except requests.exceptions.Timeout:
                timeout_time = time.time()
                self.logger.warning(f"⏰ 请求超时 (尝试 {attempt + 1})，总耗时: {timeout_time - start_time:.2f}秒")
                if attempt == self.max_retries - 1:
                    return {
                        'success': False,
                        'error': f'请求超时 (超时设置: {self.timeout}秒)',
                        'timeout': self.timeout,
                        'total_time': timeout_time - start_time
                    }

            except requests.exceptions.ConnectionError as e:
                self.logger.warning(f"🔌 连接错误 (尝试 {attempt + 1}): {str(e)[:100]}")
                if attempt == self.max_retries - 1:
                    return {
                        'success': False,
                        'error': f'无法连接到Laravel服务器: {str(e)[:100]}',
                        'endpoint': self.save_endpoint
                    }

            except Exception as e:
                self.logger.error(f"❌ 保存数据时发生错误: {e}")
                if attempt == self.max_retries - 1:
                    return {
                        'success': False,
                        'error': str(e),
                        'exception_type': type(e).__name__
                    }

        return {
            'success': False,
            'error': f'所有 {self.max_retries} 次尝试均失败'
        }

    def test_connection(self) -> bool:
        """
        测试与Laravel服务器的连接
        """
        try:
            # 发送一个简单的测试请求
            test_url = f"{self.base_url}/health"  # 假设有健康检查端点
            response = requests.get(test_url, timeout=5)

            if response.status_code == 200:
                self.logger.info("✅ Laravel服务器连接正常")
                return True
            else:
                self.logger.warning(f"⚠️ Laravel服务器响应异常: {response.status_code}")
                return False

        except Exception as e:
            self.logger.error(f"❌ 无法连接到Laravel服务器: {e}")
            return False
